﻿using System;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;
using System.Text;

using RAD.LightOne.Cache;
using System.Transactions;

namespace RAD.LightOne.Data
{
    #region Documentation
    /// <summary>
    /// Implementação própria de transação, implementa características internas importantes ao funcionameto
    /// do LightOne, externamente é e comporta-se como, uma transação normal.
    /// </summary>
    #endregion
    public sealed class MyDbTransaction : System.Data.Common.DbTransaction, IDbTransaction
    {
        #region Events
        
        public event EventHandler Commiting;
        public event EventHandler Commited;

        public event EventHandler Rollbacking;
        public event EventHandler Rollbacked;

        public event EventHandler Concluded;
        #endregion

        #region Fields

        private readonly DBEngine dbe;
        private IDbTransaction trx;
        private MyObjectsSlot slot;
        private bool scoped;
        #endregion

        #region Properties

        internal DBEngine Dbe
        {
            get { return dbe; }
        } 

        #region Documentation
        /// <summary>
        /// Retorna o slot onde os objetos criados a partir desta transação serão alocados.
        /// </summary>
        #endregion
        internal MyObjectsSlot Slot
        {
            get
            {
                //carregamento em demanda
                if (this.slot == null) this.slot = new MyObjectsSlot();

                return this.slot;
            }
        }

        #region Documentation
        /// <summary>
        /// Retorna a transação real encapsulada por esta instância, deve ser utilizada de forma restrita
        /// para casos onde seja necessário se passar realmente a transação com um tipo conhecido.
        /// </summary>
        #endregion
        internal IDbTransaction InnerTransaction
        {
            get
            {
                return this.trx;
            }
        }

        protected override DbConnection DbConnection
        {
            get { return this.scoped ? (DbConnection)this.dbe.Connection : (DbConnection)trx.Connection; }
        }


        #endregion

        #region Constructors

        internal MyDbTransaction(DBEngine dbe)
        {
            if (dbe == null) throw new ArgumentNullException("Base conn in MyDbTransaction cannot be null.");
            this.dbe = dbe;
            this.scoped = true;
            System.Transactions.Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted);
        }

        private void Current_TransactionCompleted(object sender, TransactionEventArgs e)
        {
            if (e.Transaction.TransactionInformation.Status == TransactionStatus.Committed)
            {
                if (this.Commiting != null) this.Commited(this, new EventArgs());
                if (this.Commited != null) this.Commited(this, new EventArgs());
                if (this.Concluded != null) this.Concluded(this, new EventArgs());
            }
            else if (e.Transaction.TransactionInformation.Status == TransactionStatus.Aborted)
            {
                if (this.Rollbacking != null) this.Rollbacking(this, new EventArgs());
                if (this.Rollbacked != null) this.Rollbacked(this, new EventArgs());
                if (this.Concluded != null) this.Concluded(this, new EventArgs());
            }
        }

        internal MyDbTransaction(IDbTransaction trx)
        {
            if (trx == null) throw new ArgumentNullException("Base transaction in MyDbTransaction cannot be null.");
            this.trx = trx;
            this.scoped = false;
        }

        #endregion

        #region IDbTransaction Members

        public override void Commit()
        {
            if (!this.scoped)
            {
                if (this.Commiting != null) this.Commited(this, new EventArgs());

                this.trx.Commit();

                if (this.Commited != null) this.Commited(this, new EventArgs());
                if (this.Concluded != null) this.Concluded(this, new EventArgs());
            }
        }

        public IDbConnection Connection
        {
            get { return this.scoped ? this.dbe.Connection : this.trx.Connection; }
        }

        public override System.Data.IsolationLevel IsolationLevel
        {
            get { return this.trx.IsolationLevel; }
        }

        public override void Rollback()
        {
            if (!this.scoped)
            {
                if (this.Rollbacking != null) this.Rollbacking(this, new EventArgs());

                this.trx.Rollback();

                if (this.Rollbacked != null) this.Rollbacked(this, new EventArgs());
                if (this.Concluded != null) this.Concluded(this, new EventArgs());
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (this.slot != null) this.slot.Dispose();
            if(!scoped)this.trx.Dispose();
        } 

        #endregion
    }
}
